home *** CD-ROM | disk | FTP | other *** search
- ;;; JACAL: Symbolic Mathematics System. -*-scheme-*-
- ;;; Copyright 1989, 1990, 1991, 1992 Aubrey Jaffer.
- ;;; See the file "COPYING" for terms applying to this program.
-
- ;;;; First, what case are symbols in? Determine the standard case:
- (define char-standard-case
- (cond ((not (string=? (symbol->string 'a) (symbol->string 'A)))
- char-downcase)
- ((string=? (symbol->string 'a) "A")
- char-upcase)
- ((string=? (symbol->string 'A) "a")
- char-downcase)
- (else
- char-downcase)))
- (define (string-standard-case s)
- (set! s (string-copy s))
- (do ((i 0 (+ 1 i))
- (sl (string-length s)))
- ((>= i sl) s)
- (string-set! s i (char-standard-case (string-ref s i)))))
-
- ;;;Predefined Variables and Constants
- (define newlabelstr (string-standard-case "E0"))
- (define newlabelsym (string->symbol newlabelstr))
- (define newextstr (string-standard-case "EXT_0"))
-
- (define expl_t (var->expl (sexp->var 't)))
- (define _@ (string->var ":@"))
- (define _@-pri (+ -1 char-code-limit))
- (var_set-pri! _@ _@-pri)
- (define (_@? v) (or (eq? v _@) (= (var_pri v) _@-pri)))
- (define d@ (var_differential _@)) ;used only in total-differential in norm.scm
- (var_set-pri! d@ (+ -2 char-code-limit))
- (define _@1 (string->var "@1"))
- (define _@2 (string->var "@2"))
- (define _@3 (string->var "@3"))
-
- (define __@ (string->var "::@"))
- (define _@1+@2 (list _@2 (list _@1 0 1) 1))
- (define _@1-@2 (list _@2 (list _@1 0 1) -1))
- (define _-@1 (list _@1 0 -1))
- (define _@1*@2 (list _@2 0 (list _@1 0 1)))
- (define _@1/@2 (list _@ (list _@1 0 1) (list _@2 0 -1)))
- (define _@1=@2 (list _@= _@2 (list _@1 0 -1) 1))
- (define cidentity (list _@1 0 1))
-
- ;;; canoncial functions for vect.scm
- (define _@1-@2*@3 (list _@3 (list _@1 0 1) (list _@2 0 -1)))
- (define _-@1/@2 (make-rat (list _@1 0 -1) (list _@2 0 1)))
- (define _@1*@2+@3 (list _@3 (list _@2 0 (list _@1 0 1)) 1))
-
- ;;; set up initial radical and extension
- (define %sqrt1 (defext (sexp->var '%sqrt1) (list _@ 1 0 -1)))
- (var_set-pri! %sqrt1 5)
- (define %i (defext (sexp->var '%i) (list _@ -1 0 -1)))
- (var_set-pri! %i 5)
- (define radical-defs (list (extrule %i) (extrule %sqrt1)))
- (define _+/-@1 (list _@1 0 (list %sqrt1 0 1)))
- (define _-/+@1 (list _@1 0 (list %sqrt1 0 -1)))
- (define _@1+/-@2 (list _@2 (list _@1 0 1) (list %sqrt1 0 1)))
- (define _@1-/+@2 (list _@2 (list _@1 0 1) (list %sqrt1 0 -1)))
-
- ;;; This rule can not be entered from user level.
- (define %inftsl (defext (sexp->var '%inftsl) (list _@ 0 0 1)))
-
- (define novalue (var->expl (sexp->var '?)))
- (define (novalue? x) (equal? novalue x))
- (define % novalue)
-
- (define *flags* (make-hash-table 5))
- (define flag-associator (hash-associator eq?))
- (define flag-inquirer (hash-inquirer eq?))
-
- (define (defflag name setter getter)
- (flag-associator *flags* name (cons setter getter))
- name)
-
- (define flag:setter car)
- (define flag:getter cdr)
-
- (define (flag-set name . values)
- (let ((flag (flag-inquirer *flags* name)))
- (cond ((not flag) (math:warn "flag" name "is not defined") novalue)
- ((flag:setter flag) (apply (flag:setter flag) flag values) novalue)
- (else (math:warn "flag" name "can not be set") novalue))))
-
- (define (flag-get name . rest)
- (let ((flag (flag-inquirer *flags* name)))
- (cond ((not flag) (math:warn "flag" name "is not defined") novalue)
- ((flag:getter flag) (apply (flag:getter flag) flag rest))
- (else (math:warn "flag" name "can not be read") novalue))))
-
- (defflag 'ingrammar
- (lambda (f v)
- (define name (var->sexp (explicit->var v)))
- (cond ((get-grammar name)
- (set! *input-grammar* (get-grammar name)))
- (else
- (math:warn "grammar" name "not known"))))
- (lambda (f) (var->expl (sexp->var (grammar-name *input-grammar*)))))
-
- (defflag 'outgrammar
- (lambda (f v)
- (define name (var->sexp (explicit->var v)))
- (cond ((get-grammar name)
- (set! *output-grammar* (get-grammar name)))
- (else
- (math:warn "grammar" name "not known"))))
- (lambda (f) (var->expl (sexp->var (grammar-name *output-grammar*)))))
-
- (defflag 'echogrammar
- (lambda (f v)
- (define name (var->sexp (explicit->var v)))
- (cond ((get-grammar name)
- (set! *echo-grammar* (get-grammar name)))
- (else
- (math:warn "grammar" name "not known"))))
- (lambda (f) (var->expl (sexp->var (grammar-name *echo-grammar*)))))
-
- (defflag 'grammars
- #f
- (lambda (f)
- (map (lambda (p) (var->expl (sexp->var (car p)))) *grammars*)))
-
- (define (set-boolean v)
- (define val (var->sexp (explicit->var v)))
- (case val
- ((off 0 false) #f)
- ((on 1 true) #t)
- (else (math-error "expected boolean" v))))
-
- (define (show-boolean v)
- (var->expl (string->var (if v "on" "off"))))
-
- (define horner #f)
- (defflag 'horner
- (lambda (f v) (set! horner (set-boolean v)))
- (lambda (f) (show-boolean horner)))
-
- (defflag 'trace
- (lambda (f v) (set! math_trace (set-boolean v)))
- (lambda (f) (show-boolean math_trace)))
-
- (defflag 'debug
- (lambda (f v) (set! math_debug (set-boolean v)))
- (lambda (f) (show-boolean math_debug)))
-
- (defflag 'version
- #f
- (lambda (f)
- (var->expl (string->var *jacal-version*))))
-
- (defflag 'all
- #f
- (lambda (f)
- (block-write-strings
- (sort! (map symbol->string (map car (apply append (vector->list *flags*))))
- string>?))
- novalue))
-
- (defflag 'prompt
- (lambda (f v)
- (set! newlabelstr (var->string (explicit->var v)))
- (set! newlabelsym (string->symbol newlabelstr))
- novalue)
- (lambda (f) (var->expl (string->var newlabelstr))))
-
- (defflag 'priority
- (lambda (f v p)
- (math-assert (and (number? p) (< 0 p lambda-var-pri)))
- (var_set-pri! (explicit->var v) p))
- (lambda args
- (if (null? (cdr args))
- (let ((l (apply append (map (lambda (l) (map cdr l))
- (vector->list var-tab)))))
- (block-write-strings (map object->string
- (map var->sexp (sort! l var_>))))
- novalue)
- (var_pri (explicit->var (cadr args))))))
-
- ;(define transcript-name #f)
- ;(defflag 'transcript
- ; (lambda (f v)
- ; (define file (and v (not (null? v)) (var->string (explicit->var v))))
- ; (if v (transcript-on file) (transcript-off))
- ; (set! transcript-name file))
- ; (lambda (f) (if transcript-name
- ; (var->expl (string->var transcript-name))
- ; '#())))
-
- ;;;; Built in functions
- (defbltn 'set
- (lambda (name . values)
- (apply flag-set (var->sexp (explicit->var name)) values))
- "Set options."
- '(set outgrammar scheme))
-
- (defbltn 'show
- (lambda (name . rest) (apply flag-get
- (var->sexp (explicit->var name))
- rest))
- "Show options."
- '(show outgrammar))
-
- (defbltn 'commands
- (lambda ()
- (block-write-strings
- (sort! (map object->string
- (map car (apply append (vector->list infodefs))))
- string>?))
- novalue))
-
- (defbltn '%
- (lambda 1D %)
- "Last expression")
-
- (defbltn 'describe
- (lambda (x)
- (let ((doclist (hassq (var->sexp (explicit->var x)) infodefs)))
- (for-each (lambda (i)
- (cond ((string? i) (display i))
- ((sexp? i)
- (write-sexp i *output-grammar*))
- (else (eval-error "bad info entry")))
- (newline))
- (if doclist (cdr doclist) '()))
- novalue)))
-
- (defbltn 'example
- (lambda (x)
- (let ((info (hassq (var->sexp (explicit->var x)) infodefs)))
- (do ((info (if info (cddr info) '()) (cdr info)))
- ((or (null? info) (not (string? (car info))))
- (cond ((null? info) 'no_example)
- (else (write-sexp (car info) *input-grammar*)
- (newline)
- (sexp->math (car info)))))))))
-
- (define terms
- (let ((my-vicinity (program-vicinity)))
- (lambda ()
- (call-with-input-file
- (in-vicinity my-vicinity "COPYING")
- (lambda (infile)
- (do ((c (read-char infile) (read-char infile)))
- ((eof-object? c) novalue)
- (display c)))))))
- (defbltn 'terms terms)
-
- (defbltn 'Differential
- (lambda (obj) (total-differential obj)))
-
- (defbltn 'negate
- (lambda (obj) (app* _-@1 obj))
- "Unary negation."
- '(negate a)
- '(* -1 a))
-
- (defbltn 'u+/-
- (lambda (obj) (app* _+/-@1 obj)))
-
- (defbltn 'u-/+
- (lambda (obj) (app* _-/+@1 obj)))
-
- (defbltn '^ ;need to do expt also
- (lambda (x exp)
- (if (and (expl? x) (number? exp))
- (poly_^ x (normalize exp))
- (^ (expr x) exp)))
- "Exponentiation."
- '(^ (+ a 1) 2)
- '(+ 1 a (^ a 2)))
-
- (defbltn '^^ ;need to do ncexpt also
- (lambda (a pow) (ncexpt (exprs a) (normalize pow)))
- "Non-commutative Exponentiation. For vectors, this is repeated dot
- product."
- '(^^ #(a b) 2)
- '(+ (^ a 2) (^ b 2))
- "For matrices, this is repeated matrix multiplication. If n is
- negative, the inverse of the matrix is raised to -n."
- '(^^ #(#(a b) #(c d)) 2)
- "For single-valued functions of one variable, This is the
- composition of the function with itself n times. If n is negative,
- the inverse of the function is raised to -n."
- '(^^ (lambda #(x) (+ 1 (* 2 x))) -2))
-
- (defbltn '*
- (lambda args (reduce (lambda (x y)
- (if (and (expl? x) (expl? y))
- (poly_* x y)
- (app* _@1*@2 x y)))
- args))
- "Multiplication, times."
- '(* a 7)
- '(* 7 a))
-
- (defbltn '+
- (lambda args (reduce (lambda (x y)
- (if (and (expl? x) (expl? y))
- (poly_+ x y)
- (app* _@1+@2 x y)))
- args))
- "Addition, plus."
- '(+ a b))
-
- (defbltn '-
- (lambda args (reduce (lambda (x y)
- (if (and (expl? x) (expl? y))
- (poly_- x y)
- (app* _@1-@2 x y)))
- args))
- "Subtraction, minus."
- '(- a 9))
-
- (defbltn 'b+/-
- (lambda args (reduce (lambda (x y) (app* _@1+/-@2 x y)) args)))
-
- (defbltn 'b-/+
- (lambda args (reduce (lambda (x y) (app* _@1-/+@2 x y)) args)))
-
- (defbltn '/
- (lambda args (reduce (lambda (x y) (app* _@1/@2 x y)) args))
- "Quotient, division, divide, over."
- '(/ a b))
-
- (defbltn 'bunch
- (lambda args args)
- "bunch, vector, list."
- '(bunch a b c)
- '#(a b c))
-
- (defbltn 'rapply
- (lambda args (apply rapply args))
- "subscripted reference"
- '(rapply #(a b) 2)
- 'b)
-
- (defbltn 'or
- (lambda args
- (poleqn->licit (reduce poly_* (map licit->poleqn args))))
- "union, multiple value. Or of two equations returns an equation
- with either condition true."
- '(or (= a b) (= a c))
- '(= 0 (- (^ a 2) (* b c)))
- "Or of two values yields a multiple value, such as +/-x"
- '(or x (negate x))
- '(+/- x)
- "Or of an equation and a value will yield the value.")
-
- (defbltn '=
- (lambda (x y) (app* _@1=@2 x y))
- "equals, equality. This expresses a relation between variables and
- numbers"
- '(= a (^ b 2))
- '(= 0 (- a (^ b 2)))
- "it does not conote value assignment")
-
- (defbltn 'qed
- (lambda ()
- (cleanup-handlers!)
- (math_exit #t))
- "qed, bye, exit. This leaves the math system")
-
- (defbltn 'quit
- (lambda ()
- (cleanup-handlers!)
- (quit))
- "quit. This leaves the math system and scheme")
-
- ;;;; User callable functions
-
- (defbltn 'listofvars
- (lambda (exp) (map var->expl (remove-if (lambda (x) (eq? x _@))
- (alg_vars exp))))
- "This returns a list of variables occuring in the argument"
- '(listofvars (+ a (/ b c))))
-
- (defbltn 'coeff
- (lambda (p var . optional)
- (let ((ord (if (null? optional) 1 (car optional))))
- (poly_coeff p (explicit->var var) (plicit->integer ord))))
- "coeff, coefficient. Returns the coefficient of (optional 1) power
- of var in poly")
-
- (defbltn 'num
- (lambda (exp) (num (expr_normalize exp)))
- "num, numerator, top. The numerator of a rational expression.")
-
- (defbltn 'denom
- (lambda (exp) (denom (expr_normalize exp)))
- "denom, denominator, bottom. The denominator of a rational
- expression.")
-
- (defbltn 'divide
- (lambda (dividend divisor . vars)
- (set! dividend (licit->polxpr dividend))
- (set! divisor (licit->polxpr divisor))
- (poly_pdiv dividend divisor (if (null? vars)
- (if (number? divisor)
- (if (number? dividend) 0
- (car dividend))
- (car divisor))
- (explicit->var (car vars)))))
- "divide. A bunch of the quotient and remainder.")
-
- (defbltn 'content
- (lambda (poly var)
- (let* ((var (explicit->var var))
- (poly (promote var (licit->polxpr poly)))
- (cont (apply poly_gcd* (cdr poly))))
- (list cont (poly_/ poly cont))))
- "Returns a list of content and primitive part of a polynomial with
- respect to the variable. The content is the GCD of the coefficients
- of the polynomial in the variable. The primitive part is poly divided
- by the content"
- '(content (+ (* 2 x y) (* 4 (^ x 2) (^ y 2))) y)
- '#((* x y) (+ y (* 2 x (^ y 2)))))
-
- ;;; This is user callable GCD.
- (defbltn 'gcd
- (lambda args
- (if (null? args) 0
- (reduce poly_gcd (map licit->polxpr args))))
- "gcd, greatest common divisor. The greatest common divisor of
- polynomial expressions.")
-
- (defbltn 'mod
- (lambda (licit polxpr)
- (poleqn->licit (alg_mod (licit->poleqn licit) (licit->polxpr polxpr))))
- "the first argument modulo the second argument")
-
- ;;; This is user callable RESULTANT. It always operates on
- ;;; polynomials and does not know about extensions etc.
- (defbltn 'resultant
- (lambda (a b v)
- (let ((res (poly_resultant
- (licit->polxpr a)
- (licit->polxpr b)
- (explicit->var v))))
- res))
- "resultant. The result of eliminating a variable between 2
- equations (or polynomials).")
-
- (defbltn 'sylvester
- (lambda (p1 p2 var)
- (sylvester (licit->polxpr p1)
- (licit->polxpr p2)
- (explicit->var var)))
- "sylvester. Matrix whose determinant is the resultant of 2
- equations (or polynomials).")
-
- (defbltn 'poly_discriminant
- (lambda (poly var)
- (set! poly (licit->polxpr poly))
- (set! poly (poly_/ poly (if (> (leading-number poly) 0)
- (poly_num-cont poly)
- (- (poly_num-cont poly)))))
- (let* ((v (explicit->var var))
- (deg (poly_degree poly v)))
- (if (> deg 1)
- (poly_* (quotient (* deg (- deg 1)) 2)
- (poly_resultant (poly_diff poly v) poly v))
- 0)))
- "discriminant of a polynomial. the square of the product of the
- differences of all pairs of roots."
- '(poly_discriminant (* (- x a) (- x b) (- x c)) x))
-
- (defbltn 'eliminate
- (lambda (eqns vars)
- (poleqns->licits (eliminate (licits->poleqns eqns) (variables vars))))
- "eliminate. An equation or set of equations with vars eliminated")
-
- (defbltn 'factor
- (lambda (poly)
- (let ((e (licit->polxpr poly)))
- (cond ((number? e) (require 'prime) ;autoload from SLIB
- (sort! (factor e) <))
- (else (poly_factorq e))))))
-
- (defbltn 'matrix
- (lambda args (apply matrix args))
- "matrix. makes a copy of a matrix")
-
- (defbltn 'genmatrix
- (lambda (fun i2 j2 . i1j1)
- (let ((i1 1) (j1 1))
- (cond ((null? i1j1))
- ((begin (set! i1 (car i1j1))
- (set! i1j1 (cdr i1j1))
- (set! j1 i1)
- (null? i1j1)))
- ((begin (set! j1 (car i1j1))
- (set! i1j1 (cdr i1j1))
- (null? i1j1)))
- (else (math-error "Too many arguments")))
- (mtrx_genmatrix
- fun
- (plicit->integer i2)
- (plicit->integer j2)
- (plicit->integer i1)
- (plicit->integer j1))))
- "genmatrix. A matrix whose entries are the function applied to its indices")
-
- (defbltn 'ident
- (lambda (n) (mtrx_scalarmatrix n 1))
- "ident, identity matrix. A square matrix of 0s except the diagonal
- entries are 1")
-
- (defbltn 'scalarmatrix
- (lambda (n x) (mtrx_scalarmatrix (plicit->integer n) x))
- "scalarmatrix, diagonal matrix. A square matrix of 0s except the
- diagonal entries = argument")
-
- (defbltn 'diagmatrix
- (lambda args (mtrx_diagmatrix args))
- "diagmatrix takes as input a list of algebraic values and returns
- a diagonal matrix whose diagonal entries are the elements of that
- list.")
-
- (defbltn 'determinant
- (lambda (m) (determinant m))
- "determinant. The determinant of a square matrix")
-
- (defbltn 'crossproduct
- (lambda (x y) (crossproduct x y))
- "crossproduct. Crossproduct of 2 vectors")
-
- (defbltn 'dotproduct
- (lambda (x y) (dotproduct x y))
- "dotproduct. dotproduct of 2 vectors.")
-
- (defbltn 'ncmult
- (lambda (x y) (ncmult x y))
- "ncmult. non-commutative matrix multiplication of 2 vectors.")
-
- (defbltn 'row
- (lambda (m i)
- (if (matrix? m)
- (list-ref m (+ -1 (plicit->integer i)))
- (math-error "Row of non-matrix?: " M)))
- "Row. row of a matrix")
-
- (defbltn 'col
- (lambda (m i)
- (cond ((matrix? m)
- (map (lambda (row)
- (list (list-ref row (+ -1 (plicit->integer i)))))
- m))
- ((bunch? m) (list-ref m (plicit->integer i)))
- (else (math-error "Column of non-matrix?: " M))))
- "column. column of a matrix")
-
- (defbltn 'minor
- (lambda (m i j)
- (mtrx_minor m (plicit->integer i) (plicit->integer j)))
- "minor. minor of a matrix")
-
- (defbltn 'transpose
- (lambda (m) (transpose m))
- "transpose. transpose of a matrix")
-
- (defbltn 'finv
- (lambda (f)
- (fcinverse f)))
-
- (defbltn 'load
- (lambda (file)
- (load (var->string (explicit->var file)))
- file))
-
- (defbltn 'batch
- (lambda (file)
- (batch (var->string (explicit->var file)))))
-
- (define wna "Wrong number of args to ")
-
- (defbltn 'transcript
- (lambda files
- (cond ((null? files)
- (transcript-off)
- novalue)
- (else
- (math-assert (null? (cdr files)) wna 'transcript files)
- (let ((file (var->string (explicit->var (car files)))))
- (transcript-on file)
- (car files))))))
-
- (defbltn 'system
- (lambda (command)
- (system (var->string (explicit->var command)))
- ; command ;uncomment this line if system doesn't return nicely
- ))
-
- (defbltn 'coeffs
- (lambda (poly var)
- (math-assert (and (expl? poly) (not (number? poly)))
- "not a polynomial?" poly)
- (cdr (promote (explicit->var var) poly))))
-
- (defbltn 'poly
- (lambda (var . args)
- (reduce (lambda (p c) (poly_+ (poly_* p var) c))
- (cond ((> (length args) 1) args)
- (else
- (math-assert (and (= (length args) 1) (bunch? (car args)))
- "not a bunch?" (car args))
- (car args))))))
-
- (defbltn 'diff
- (lambda (exp . args)
- (reduce-init diff exp (map explicit->var args))))
-
- ;(defbltn 'partial
- ; (lambda (func arg . args)
- ; (math-assert (clambda? func) "not a function?" func)
- ; (math-assert (> (length args) 0) "no variables?")
- ; (reduce-init partial
- ; (explicit->var func)
- ; (explicit->var arg)
- ; (map explicit->var args))))
-